package com.wang.jmonkey.ca.handler.login.success;

import com.alibaba.fastjson.JSONObject;
import com.wang.jmonkey.ca.model.AuthInfo;
import com.wang.jmonkey.ca.service.SystemUserService;
import com.wang.jmonkey.common.constant.CacheConstant;
import com.wang.jmonkey.common.model.vo.PermissionVo;
import com.wang.jmonkey.common.model.vo.UserVo;
import com.wang.jmonkey.common.result.HttpResult;
import com.wang.jmonkey.common.utils.UserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @Description 登录成功操作
 * @Author HeJiawang
 * @Date 2021/5/14 9:32
 */
@Slf4j
@Component
public class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private TokenBuildHandlerManager tokenBuildHandlerManager;

    @Autowired
    private RedisTemplate<String , Object> redis;

    @Autowired
    private SystemUserService systemUserService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {
        HttpResult<AuthInfo> result = new HttpResult<>();

        try {

            OAuth2AccessToken oauth2AccessToken = tokenBuildHandlerManager.handler(request, authentication);
            String userName = UserUtil.Info.getUsername(oauth2AccessToken.getValue());

            UserVo userVo = redis.execute(new SessionCallback<>() {

                @Override
                public UserVo execute(RedisOperations operations) throws DataAccessException {
                    UserVo userVo = systemUserService.selectUserVo(userName);
                    operations.opsForHash().put(CacheConstant.PermissionCache.USER_INFO.getKey(), userName, userVo);

                    Map<String, List<String>> permissionMap = systemUserService.selectPermission(userVo);
                    operations.opsForHash().put(CacheConstant.PermissionCache.USER_PERMISSION.getKey(), userName, permissionMap);

                    return userVo;
                }
            });

            result.setData(
                    new AuthInfo()
                            .setAccessToken(oauth2AccessToken.getValue())
                            .setRefreshToken(oauth2AccessToken.getRefreshToken().getValue())
                            .setUser(userVo)
            );

        }
        catch (InvalidGrantException e) {

            log.error(this.getClass().getName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName(), e);
            result.error("refresh_token过期，获取access_token失败");
        }
        catch (Exception e) {

            log.error(this.getClass().getName() + "." + Thread.currentThread().getStackTrace()[1].getMethodName(), e);
            result.error(e.getMessage());
        }

        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        response.getWriter().write(JSONObject.toJSONString(result));
    }

}
